//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "pthread.h"
#include "pcentral.h"
#include <aura.h>

#define Lock(hCritical)     do { \
                                AuraCriticalSection_Enter(hCritical); \
                            } while(0)

#define Unlock(hCritical)   do { \
                                AuraCriticalSection_Leave(hCritical); \
                            } while(0)

#define REMOTE_PROCESS_ALREADY_EXITED() (NULL == m_pProxy)
#define REMOTE_PROCESS_JUST_EXITED(ec)  (E_PROCESS_ALREADY_EXITED == ec)

CPseudoThread::~CPseudoThread()
{
    if (NULL != m_hLock) {
        AuraCriticalSection_Destroy(m_hLock);
        m_hLock = NULL;
    }
}

ECode CPseudoThread::Initialize()
{
    ECode ec = NOERROR;

    ec = AuraCriticalSection_Create(&m_hLock);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    assert(NULL != m_pProxy);
    ec = m_pProxy->GetId(&m_threadId);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    ec = CPseudoCentral::Thread_AddRef(m_threadId,m_ownerPid);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    return ec;

ErrorExit:
    if (NULL != m_hLock) {
        AuraCriticalSection_Destroy(m_hLock);
        m_hLock = NULL;
    }
    return ec;
}

PInterface CPseudoThread::Probe(
    /* [in] */ REIID riid)
{
    if (riid == EIID_IInterface) {
        return (PInterface)(IThread *)this;
    }
    else if (riid == EIID_IThread) {
        return (IThread *)this;
    }
    else if (riid == EIID_CLASS_INFO) {
        return (PInterface)&ECLSID_CThread;
    }
    else if (riid == EIID_INTERFACE_INFO) {
        return (PInterface)&EIID_IThread;
    }

    return NULL;
}

UInt32 CPseudoThread::AddRef()
{
    Int32 nRef = m_Refs.Increment();
    return (UInt32)nRef;
}

UInt32 CPseudoThread::Release()
{
    Int32 nRef;
    nRef = m_Refs.Decrement();
    if (0 >= nRef) {
        PseudoObject::S_Delete(PseudoObjectType_Thread, this);
        Lock(m_hLock);
        if (NULL != m_pProxy) {
            m_pProxy->Release();
            m_pProxy = NULL;
        }
        else {
            CPseudoCentral::Thread_Release(m_threadId);
        }
        Unlock(m_hLock);
        delete this;
    }
    return (UInt32)nRef;
}

ECode CPseudoThread::Aggregate(
    /* [in] */ AggrType aggrType,
    /* [in] */ PInterface pObject)
{
    return E_NOT_IMPLEMENTED;
}

ECode CPseudoThread::GetDomain(
    /* [out] */ PInterface *ppObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode CPseudoThread::Start()
{
    ECode ec = NOERROR;

    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    ec = m_pProxy->Start();
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        goto RemoteProcessExited;
    }
    Unlock(m_hLock);
    return ec;

RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock(m_hLock);
    return E_PROCESS_ALREADY_EXITED;
}

ECode CPseudoThread::Suspend()
{
    ECode ec = NOERROR;

    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    ec = m_pProxy->Suspend();
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        goto RemoteProcessExited;
    }
    Unlock(m_hLock);
    return ec;

RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock(m_hLock);
    return E_PROCESS_ALREADY_EXITED;
}

ECode CPseudoThread::Resume()
{
    ECode ec = NOERROR;

    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    ec = m_pProxy->Resume();
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        goto RemoteProcessExited;
    }
    Unlock(m_hLock);
    return ec;

RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock(m_hLock);
    return E_INVALID_OPERATION;
}

ECode CPseudoThread::Join(
    /* [in]  */ Millisecond32 timeout,
    /* [out] */ WaitResult *pResult)
{
    ECode ec = NOERROR;

    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    Unlock(m_hLock);
    // BUG here (NULL == m_pProxy), but rarely happen.
    ec = m_pProxy->Join(timeout, pResult);
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        Lock(m_hLock);
        goto RemoteProcessExited;
    }
    return ec;

RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock(m_hLock);
    *pResult = WaitResult_OK;
    return NOERROR;
}

ECode CPseudoThread::Interrupt()
{
    ECode ec = NOERROR;

    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    ec = m_pProxy->Interrupt();
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        goto RemoteProcessExited;
    }
    Unlock(m_hLock);
    return ec;

RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock(m_hLock);
    return E_THREAD_ALREADY_FINISHED;
}

ECode CPseudoThread::Quit()
{
    return E_NOT_IMPLEMENTED;
}

ECode CPseudoThread::Abort()
{
    ECode ec = NOERROR;

    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    ec = m_pProxy->Abort();
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        goto RemoteProcessExited;
    }
    Unlock(m_hLock);
    return ec;

RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock(m_hLock);
    return E_THREAD_ALREADY_FINISHED;
}

ECode CPseudoThread::SetPriority(
    /* [in] */ ThreadPriority priority)
{
    ECode ec = NOERROR;

    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    ec = m_pProxy->SetPriority(priority);
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        goto RemoteProcessExited;
    }
    Unlock(m_hLock);
    return ec;

RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock(m_hLock);
    return E_THREAD_ALREADY_FINISHED;
}

ECode CPseudoThread::GetPriority(
    /* [out] */ ThreadPriority * pPriority)
{
    ECode ec = NOERROR;

    if (NULL == pPriority) {
        return E_INVALID_ARGUMENT;
    }

    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    ec = m_pProxy->GetPriority(pPriority);
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        goto RemoteProcessExited;
    }
    Unlock(m_hLock);
    return ec;

RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock(m_hLock);
    return E_THREAD_ALREADY_FINISHED;
}

ECode CPseudoThread::GetId(
    /* [out] */ ThreadId * pTid)
{
    if (NULL == pTid) {
        return E_INVALID_ARGUMENT;
    }

    *pTid = m_threadId;
    return NOERROR;
}

ECode CPseudoThread::SetName(
    /* [in] */ WString name)
{
    ECode ec = NOERROR;

    if (name.IsNullOrEmpty()
        || (name.GetLength(MAXIMUM_THREAD_NAME_LENGTH) < 0)) {
        return E_INVALID_ARGUMENT;
    }

    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    ec = m_pProxy->SetName(name);
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        goto RemoteProcessExited;
    }
    Unlock(m_hLock);
    return ec;

RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock(m_hLock);
    return E_THREAD_ALREADY_FINISHED;
}

ECode CPseudoThread::GetName(
    /* [out] */ WStringBuf * pName)
{
    ECode ec = NOERROR;

    if ((NULL == pName) || !pName->GetCapacity()) {
        return E_INVALID_ARGUMENT;
    }

    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    ec = m_pProxy->GetName(pName);
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        goto RemoteProcessExited;
    }
    Unlock(m_hLock);
    return ec;

RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock(m_hLock);
    return CPseudoCentral::Thread_GetName(m_threadId, pName);
}

ECode CPseudoThread::GetState(
    /* [out] */ ThreadState * pState)
{
    ECode ec = NOERROR;

    if (NULL == pState) {
        return E_INVALID_ARGUMENT;
    }

    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    ec = m_pProxy->GetState(pState);
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        goto RemoteProcessExited;
    }
    Unlock(m_hLock);
    return ec;

 RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock(m_hLock);
    *pState = ThreadState_Finished;
    return NOERROR;
}

ECode CPseudoThread::GetQuitCode(
    /* [out] */ QuitCode * pQuitCode)
{
    ECode ec = NOERROR;

    if (NULL == pQuitCode) {
        return E_INVALID_ARGUMENT;
    }

    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    ec = m_pProxy->GetQuitCode(pQuitCode);
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        goto RemoteProcessExited;
    }
    Unlock(m_hLock);
    return ec;

RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    return CPseudoCentral::Thread_GetQuitCode(m_threadId, pQuitCode);
}

ECode CPseudoThread::GetStartTime(
    /* [out] */ SystemTime * pTime)
{
    ECode ec = NOERROR;

    if (NULL == pTime) {
        return E_INVALID_ARGUMENT;
    }

    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    ec = m_pProxy->GetStartTime(pTime);
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        goto RemoteProcessExited;
    }
    Unlock(m_hLock);
    return ec;

RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock(m_hLock);
    return CPseudoCentral::Thread_GetStartTime(m_threadId, pTime);
}

ECode CPseudoThread::GetQuitTime(
    /* [out] */ SystemTime * pTime)
{
    ECode ec = NOERROR;

    if (NULL == pTime) {
        return E_INVALID_ARGUMENT;
    }

    Lock(m_hLock);
    if (REMOTE_PROCESS_ALREADY_EXITED()) {
        goto RemoteProcessExited;
    }
    ec = m_pProxy->GetQuitTime(pTime);
    if (REMOTE_PROCESS_JUST_EXITED(ec)) {
        goto RemoteProcessExited;
    }
    Unlock(m_hLock);
    return ec;

RemoteProcessExited:
    if (NULL != m_pProxy) {
        m_pProxy->Release();
        m_pProxy = NULL;
    }
    Unlock(m_hLock);
    return CPseudoCentral::Thread_GetQuitTime(m_threadId, pTime);
}

ECode CPseudoThread::GetProcessorTimes(
    /* [out] */ Millisecond32 * pUserTime,
    /* [out] */ Millisecond32 * pKernelTime)
{
    return E_NOT_IMPLEMENTED;
}

ECode CPseudoThreadFactory::CreateObject(
    /* [out] */ PseudoObject ** ppPseudoObject)
{
    CPseudoThread * pThread = NULL;
    ECode ec = NOERROR;

    assert(NULL != ppPseudoObject);

    pThread = new CPseudoThread(m_processId, m_pProxy);
    if (NULL == pThread) {
        return E_OUT_OF_MEMORY;
    }
    ec = pThread->Initialize();
    if (FAILED(ec)) {
        delete pThread;
        return ec;
    }
    pThread->AddRef();
    *ppPseudoObject = pThread;

    return NOERROR;
}

